use rand::Rng;
use std::cmp::Ordering;
use std::io;
use std::{thread, time};

fn main() {
    println!("Hello, world!");

    let s1 = String::from("hello");
    let s2 = "hello";
    println!("s1 {}", s1);
    println!("s2 {}", s2);

    let mut s3 = String::from("hello");
    s3.push_str(", world!"); // push_str() 在字符串后追加字面值
    println!("s3 {}", s3); // 将打印 `hello, world!`

    let s111 = String::from("hello");
    let s211 = s111.clone();
    println!("s111 = {}, s211 = {}", s111, s211);

    let x: i32 = 5;
    let y = x;
    println!("x = {}, y = {}", x, y);

    let s11 = String::from("hello");
    let s21 = s11;
    println!("{}, world!", s21);

    let c1 = 'h';
    let c2 = c1;
    println!("char: {}, {} world!", c1, c2);

    // 旧值会被回收
    let s11 = String::from("hello");
    let s21 = s11;
    // s11 无效
    println!("{}, world!", s21);

    // 带有所有权和作用域注释的函数
    owener();

    returnOwener();

    reference();

    // 可变引用
    mutReference();
}

// 带有所有权和作用域注释的函数
fn owener() {
    let s = String::from("hello"); // s 进入作用域

    takes_ownership(s); // s 的值移动到函数里 ...
                        // ... 所以到这里 s 不再有效， 使用会报错
    // 当尝试在调用 takes_ownership 后使用 s 时，Rust 会抛出一个编译时错误。这些静态检查使我们免于犯错。

    let x = 5; // x 进入作用域

    makes_copy(x); // x 应该移动函数里，
                   // 但 i32 是 Copy 的， 所以在后面可继续使用 x
    println!("{}, x!", x);
} // 这里, x 先移出了作用域，然后是 s。但因为 s 的值已被移走，
  // 没有特殊之处

fn takes_ownership(some_string: String) {
    // some_string 进入作用域
    println!("{}", some_string);
} // 这里，some_string 移出作用域并调用 `drop` 方法。
  // 占用的内存被释放

fn makes_copy(some_integer: i32) {
    // some_integer 进入作用域
    println!("{}", some_integer);
} // 这里，some_integer 移出作用域。没有特殊之处




// 返回值也可以转移所有权
fn returnOwener() {
    let s1 = gives_ownership();         // gives_ownership 将返回值 转移给 s1
    println!("gives_ownership s1:{}", s1);

    let s2 = String::from("hello");     // s2 进入作用域

    // s2 被移动到  takes_and_gives_back 中, 它也将返回值移给 s3
    let s3 = takes_and_gives_back(s2);    // gives_ownership 将返回值 转移给 s1
    // 这里 s2 已经失效

    println!("gives_ownership s3:{}", s3);
} // 这里, s3 移出作用域并被丢弃。s2 也移出作用域，但已被移走，
// 所以什么也不会发生。s1 离开作用域并被丢弃

fn gives_ownership() -> String {             // gives_ownership 会将 返回值移动给 调用它的函数
    let some_string = String::from("yours"); // some_string 进入作用域.

    println!("gives_ownership some_string:{}", some_string);
    some_string         // 返回 some_string 并移出给调用的函数
}

// takes_and_gives_back 将传入字符串并返回该值
fn takes_and_gives_back(a_string: String) -> String { // a_string 进入作用域

    a_string  // 返回 a_string 并移出给调用的函数
}


///////////////////////////////////////////////////////////
// 引用
///////////////////////////////////////////////////////////
fn reference() {
    let s1 = String::from("hello");

    // &s1 语法让我们创建一个 指向 值 s1 的引用，但是并不拥有它。
    // 因为并不拥有这个值，所以当引用停止使用时，它所指向的值也不会被丢弃。
    let len = calculate_length_reference(&s1);

    println!("reference The length of '{}' is {}.", s1, len);
}

fn calculate_length_reference(s: &String) -> usize { // s is a reference to a String
    // （默认）不允许修改引用的值。

    s.len()
}  // 这里，s 离开了作用域。但因为它并不拥有引用值的所有权，
// 所以什么也不会发生

///////////////////////////////////////////////////////////
// 可变引用
///////////////////////////////////////////////////////////
fn mutReference() {
    let mut s1 = String::from("hello");

    // &s1 语法让我们创建一个 指向 值 s1 的引用，但是并不拥有它。
    // 因为并不拥有这个值，所以当引用停止使用时，它所指向的值也不会被丢弃。
    let len = calculate_length_mutReference(&mut s1);

    println!("mutReference The length of '{}' is {}.", s1, len);


    let r1 = &mut s1;
    let r2 = &mut s1;
    println!("{}", r2);
}

fn calculate_length_mutReference(s: &mut String) -> usize { // s is a reference to a String
    s.push_str(", world");

    s.len()
}  // 这里，s 离开了作用域。但因为它并不拥有引用值的所有权，
// 所以什么也不会发生